package org.odst.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.odftoolkit.odfdom.doc.table.OdfTableCell;
import org.odftoolkit.odfdom.doc.table.OdfTableRow;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElementBase;
import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableHeaderRowsElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowGroupElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowsElement;
import org.odst.formula.Formula;
import org.odst.formula.TemplateSheetResolver;
import org.odst.parser.CellParser;
import org.odst.transformer.Row;
import org.odst.transformer.Sheet;
import org.w3c.dom.Node;

/**
 * @author Leonid Vysochyn
 * @author Cyril PODER
 */
public class SheetHelper {

    protected static final Log log = LogFactory.getLog(SheetHelper.class.getName());


    public static List<Formula> findFormulas(Sheet sheet, Map<String, List<String>> sheetMapping){
    	List<Formula> formulas = new ArrayList<Formula>();
    	OdfTableRow row = sheet.getOooSheet().getRowByIndex(0);
    	while (row != null) {
    		OdfTableCell cell = row.getCellByIndex(0);
    		while (cell != null) {
				if (cell.getStringValue().startsWith(sheet.getConfiguration().getStartFormulaToken())) {
					CellParser cellParser = new CellParser(cell, new Row(sheet, row), sheet.getConfiguration());
					Formula formula = cellParser.parseCellFormula();
					if (formula != null) {
						TemplateSheetResolver.updateTemplateSheetRefs(formula, sheetMapping);
						cell.setStringValue(sheet.getConfiguration().getStartFormulaToken() + formula.getFormula() + sheet.getConfiguration().getEndFormulaToken() + (cellParser.getCell().getMetaInfo() != null && !cellParser.getCell().getMetaInfo().isEmpty() ? cellParser.getCell().getMetaInfo() : ""));
			            if( !formula.isInline() ) {
			                formula.setSheet( sheet );
			                formulas.add( formula );
			            }
					}
				}
				cell = getNextCell(cell);
			}
    		row = getNextRow(row);
    	}
    	return formulas;
    }

	public static OdfTableCell getNextCell(OdfTableCell cell) {
    	OdfTableCell result = null;
		Node nextCell = cell.getOdfElement().getNextSibling();
		if (nextCell != null && nextCell instanceof TableTableCellElementBase)
			result = OdfTableCell.getInstance((TableTableCellElementBase)nextCell);
		return result;
    }
    
    public static OdfTableRow getNextRow(OdfTableRow row) {
    	Node nextSibling = getNextSibling(row.getOdfElement());
    	return nextSibling == null ? null : OdfTableRow.getInstance((TableTableRowElement)nextSibling);
    }
    
    private static Node getNextSibling(Node node) {
    	Node result = null;
		Node nextRow = node.getNextSibling();
		if (nextRow != null) {
			if (nextRow instanceof TableTableRowElement)
				result = nextRow;
			else if (nextRow instanceof TableTableRowGroupElement
					|| nextRow instanceof TableTableRowsElement
					|| nextRow instanceof TableTableHeaderRowsElement) {
				while (!(nextRow instanceof TableTableRowElement) && !(nextRow instanceof TableTableElement))
					nextRow = nextRow.getParentNode();
				if (nextRow instanceof TableTableRowElement)
					result = nextRow;
			}
		} else {
			nextRow = node.getParentNode();
			if (!(nextRow instanceof TableTableElement))
				result = getNextSibling(nextRow);
		}
		return result;
    }
}
